// $codepro.audit.disable
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import edu.gatech.spacetraderteam3.controller.GUIEventHandler;
import edu.gatech.spacetraderteam3.view.Assets;
import edu.gatech.spacetraderteam3.view.SGGWM;
import edu.gatech.spacetraderteam3.view.ViewSystem;

public class ForceFieldsDemo extends JPanel {
    public static void main(String[] args) throws IOException {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame demo = new JFrame("Force Fields");
                demo.setMinimumSize(new Dimension(800, 600));
                demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                ForceFieldsDemo contentPanel = new ForceFieldsDemo();
                SGGWM.registerContainer(contentPanel);
                BufferedImage cursorImage = Assets.CursorType.MAIN.image();
                Cursor cursor = Toolkit.getDefaultToolkit()
                        .createCustomCursor(cursorImage, new Point(0, 0), "Main Cursor");
                contentPanel.setCursor(cursor);
                contentPanel.addKeyListener(GUIEventHandler.getKeyListener());
                demo.add(contentPanel);
                demo.pack();
                demo.setVisible(true);
                contentPanel.requestFocusInWindow();
            }
        });
    }

    private ViewSystem systemView;
    private ForceField forceField;

    public ForceFieldsDemo() {
        systemView = new ViewSystem() {
        };
        systemView.setAction(true);
        forceField = new ForceField(300, 300, 350, 350);
        MouseAdapter mA = new MouseAdapter() {
            public void mouseReleased(MouseEvent m) {
                forceField.takeHit(m.getPoint());
            }
        };
        addMouseListener(mA);
        addMouseMotionListener(mA);
        new Timer(10, new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                forceField.fade();
                repaint();
            }
        }).start();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        systemView.paint(g2);
        forceField.setLocation(100, 100);
        forceField.paint(g2);
        Toolkit.getDefaultToolkit().sync();
        g2.dispose();
    }

    private class ForceField {
        private double hitTheta;
        private HashMap<Point, Integer> hits;
        private Color hitColor = Color.WHITE;
        private Color fade;
        private Color normal = new Color(0, 0, 0, 0);
        private Color fillColor = new Color(100, 170, 200, 100);
        private int x, y, wid, hei;
        private int fadeSpeed = 20;

        public ForceField(int x, int y, int wid, int hei) {
            this.x = x;
            this.y = y;
            this.wid = wid;
            this.hei = hei;
            fade = normal;
            hits = new HashMap<Point, Integer>();
        }

        public void setLocation(int x, int y) {
            this.x = x;
            this.y = y;
            // for (Point hP : hits.keySet()) {
            // hP.setLocation(hP.getX() + dX, hP.getY() + dY);
            // }
        }

        public void paint(Graphics2D g) {
            float radius = Math.max(wid / 2, hei / 2); // TODO: should be calculated by damage to shield
            float[] dist = { 0.98f, 1.00f };
            Color[] colors = { fillColor, normal };
            RadialGradientPaint radialPaint = new RadialGradientPaint(new Point(x + wid
                    / 2, y + hei / 2), radius, dist, colors);
            g.setPaint(radialPaint);
            g.fillOval(x, y, wid, hei);
            for (Point center : hits.keySet()) {
                fade = new Color(fade.getRed(), fade.getGreen(), fade.getBlue(),
                        hits.get(center));
                radius = 100; // TODO: should be calculated by damage to shield
                dist = new float[] { 0.01f, .8f };
                colors = new Color[] { fade, normal };
                radialPaint = new RadialGradientPaint(getEntryPoint(center), radius,
                        dist, colors);
                g.setPaint(radialPaint);
                g.fillOval(x, y, wid, hei);
            }
        }

        public void takeHit(Point p) {
            fade = hitColor;
            hits.put(p, 0xFF);
        }

        public void fade() {
            fade.darker();
            ArrayList<Point> remove = new ArrayList<Point>();
            for (Point hP : hits.keySet()) {
                hits.put(hP, Math.max(hits.get(hP) - fadeSpeed, 0));
                if (hits.get(hP) <= 0) {
                    remove.add(hP);
                }
            }
            for (Point hP : remove) {
                hits.remove(hP);
            }
        }

        private Point getEntryPoint(Point p) {
            double oCX = x + wid / 2;
            double oCY = y + hei / 2;
            double mX = p.getX();
            double mY = p.getY();

            double a = wid / 2, b = hei / 2;

            hitTheta = Math.atan2(mY - oCY, mX - oCX);
            double x0 = Math.cos(hitTheta) * 10;
            double y0 = Math.sin(hitTheta) * 10;

            int x = (int) ((a * b / (Math.sqrt(a * a * y0 * y0 + b * b * x0 * x0)) * x0) + oCX);
            int y = (int) ((a * b / (Math.sqrt(a * a * y0 * y0 + b * b * x0 * x0)) * y0) + oCY);
            return new Point(x, y);
        }
    }
}
